/*++

Copyright (c) Microsoft Corporation. All rights reserved. 

You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.


Module Name:

    PnP.c

Abstract:

    The PnP package provides a method for file systems to 
    notify applications and services that a volume is being
    locked or unlocked, so handles to it can be closed and
    reopened.
    
    This module exports routines which help file systems
    do this notification.

--*/

#include "FsRtlP.h"

#ifndef FAR
#define FAR
#endif
#include <IoEvent.h>

#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, FsRtlNotifyVolumeEvent)
#endif


NTKERNELAPI
NTSTATUS
FsRtlNotifyVolumeEvent (
    __in PFILE_OBJECT FileObject,
    __in ULONG EventCode
    )

/*++

Routine Description:

    This routine notifies any registered applications that a 
    volume is being locked, unlocked, etc.  

Arguments:

    FileeObject - Supplies a file object for the volume being
        locked.

    EventCode - Which event is occurring -- e.g. FSRTL_VOLUME_LOCK
        
Return Value:

    Status of the notification.

--*/

{
    NTSTATUS Status = STATUS_SUCCESS;

    TARGET_DEVICE_CUSTOM_NOTIFICATION Event;
    PDEVICE_OBJECT Pdo;

    //
    //  Retrieve the device object associated with this file object.
    //

    Status = IoGetRelatedTargetDevice( FileObject, &Pdo );

    if (NT_SUCCESS( Status )) {

        ASSERT(Pdo != NULL);

        Event.Version = 1;
        Event.FileObject = NULL;
        Event.NameBufferOffset = -1;
        Event.Size = (USHORT)FIELD_OFFSET( TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer );

        switch (EventCode) {

        case FSRTL_VOLUME_DISMOUNT:
            
            RtlCopyMemory( &Event.Event, &GUID_IO_VOLUME_DISMOUNT, sizeof( GUID ));
            break;
            
        case FSRTL_VOLUME_DISMOUNT_FAILED:
            
            RtlCopyMemory( &Event.Event, &GUID_IO_VOLUME_DISMOUNT_FAILED, sizeof( GUID ));
            break;            

        case FSRTL_VOLUME_LOCK:
        
            RtlCopyMemory( &Event.Event, &GUID_IO_VOLUME_LOCK, sizeof( GUID ));
            break;

        case FSRTL_VOLUME_LOCK_FAILED:
        
            RtlCopyMemory( &Event.Event, &GUID_IO_VOLUME_LOCK_FAILED, sizeof( GUID ));
            break;
        
        case FSRTL_VOLUME_MOUNT:
            
            //
            //  Mount notification is asynchronous to avoid deadlocks when someone 
            //  unwittingly causes a mount in the course of handling some other
            //  PnP notification, e.g. MountMgr's device arrival code.
            //
            
            RtlCopyMemory( &Event.Event, &GUID_IO_VOLUME_MOUNT, sizeof( GUID ));
            IoReportTargetDeviceChangeAsynchronous( Pdo, &Event, NULL, NULL );
            ObDereferenceObject( Pdo );
            return STATUS_SUCCESS;
            break;

        case FSRTL_VOLUME_UNLOCK:
        
            RtlCopyMemory( &Event.Event, &GUID_IO_VOLUME_UNLOCK, sizeof( GUID ));
            break;
            
        default:

            ObDereferenceObject( Pdo );
            return STATUS_INVALID_PARAMETER;
        }
        
        IoReportTargetDeviceChange( Pdo, &Event );
        ObDereferenceObject( Pdo );
    }

    return Status;
}

